package com.snl.micro.blog.article.base;

import com.snl.micro.blog.article.client.UserClient;
import com.snl.micro.blog.article.dao.mapper.ArticleMapper;
import com.snl.micro.blog.article.pojo.enmu.Theme;
import com.snl.micro.blog.article.pojo.po.ArticlePo;
import com.snl.micro.blog.common.action.Action;
import com.snl.micro.blog.common.protocol.ResponseResult;
import com.snl.micro.blog.common.query.ArticleQueryParam;
import com.snl.micro.blog.common.query.CommentQuery;
import com.snl.micro.blog.common.query.TagQuery;
import com.snl.micro.blog.common.query.UserQuery;
import com.snl.micro.blog.common.vo.CommentVo;
import com.snl.micro.blog.common.vo.TagVo;
import com.snl.micro.blog.common.vo.UserVo;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.*;

@Data
@Component
@AllArgsConstructor
public class ScheThread {

    private ScheduledExecutorService scheduledExecutorService;

    @Autowired
    private ArticleMapper articleMapper;

    private BlockingQueue<Integer> themesCount;

    private ExecutorService executorService;

    @Autowired
    private UserClient userClient;


    public ScheThread() {
        this.scheduledExecutorService = Executors.newScheduledThreadPool(10);
        this.themesCount = new ArrayBlockingQueue<>(Theme.values().length);
        this.executorService = Executors.newCachedThreadPool();
        this.run();
    }

    public void run() {
            ArticleQueryParam queryParam = new ArticleQueryParam();
            this.scheduledExecutorService.scheduleAtFixedRate(task(queryParam),1,10,TimeUnit.SECONDS);
    }

    public Runnable task(ArticleQueryParam queryParam) {
        return ()->{
            Arrays.stream(Theme.values()).forEach(theme -> {
                queryParam.setThemeCode(theme.getCode());
                List<ArticlePo> query = this.articleMapper.query(queryParam);
                try {
                    if (themesCount.remainingCapacity()<1) {
                        themesCount.take();
                        themesCount.put(query.size());
                    } else {
                        themesCount.put(query.size());
                    }

                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        };
    }

    private Callable<List<TagVo>> findTagsByArticleId(TagQuery query) {
        return ()-> articleMapper.selectTags(query);
    }

    public List<TagVo> runTag(TagQuery query)  {
        Future<List<TagVo>> submit =
                this.executorService.submit(findTagsByArticleId(query));
        try {
            return submit.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }



    private Callable<List<UserVo>> findUser(UserQuery query) {
        return ()->{
            ResponseResult<List<UserVo>> responseResult = userClient.query(query);
            return responseResult.getData();
        };
    }


    public List<UserVo> getUserVo(UserQuery query) {
        Future<List<UserVo>> submit = this.executorService.submit(findUser(query));
        try {
            return submit.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    private Callable<Integer> countLikes(Long articleId) {
        return ()->articleMapper.countLikes(articleId);
    }

    private Callable<Integer> countHates(Long articleId) {
        return ()->articleMapper.countHates(articleId);
    }

    public HashMap<Action,Integer> countLikesAndHates(Long articleId) {
        HashMap<Action,Integer> counts = new HashMap<>();
        Future<Integer> likesFuture =
                this.executorService.submit(countLikes(articleId));
        Future<Integer> hatesFuture =
                this.executorService.submit(countHates(articleId));

        try {
            Integer likes = likesFuture.get();
            Integer hates = hatesFuture.get();
            counts.put(Action.LIKE,likes);
            counts.put(Action.HATE,hates);
            return counts;
        } catch (ExecutionException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    //找到关于该文章的所有评论
    private Callable<List<CommentVo>> findComments(CommentQuery query) {
        return ()->{
            ResponseResult<List<CommentVo>> result = userClient.query(query);
            return result.getData();
        };
    }

    //获取该文章的所有评论
    public List<CommentVo> getComments(CommentQuery query) {
        Future<List<CommentVo>> future =
                this.executorService.submit(findComments(query));
        try {
            return future.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    //线程调度
    private Callable<List<TagVo>> findTags(TagQuery query) {
        return ()->articleMapper.selectAllTags(query);
    }

    //获取特定主题的标签
    public List<TagVo> getTags(TagQuery query) {
        Future<List<TagVo>> tagsFuture =
                this.executorService.submit(findTags(query));
        try {
            return  tagsFuture.get();

        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    public void insertArticleTag(Long articleId,List<Integer> tagCode) {
        if ( Objects.isNull(tagCode)||tagCode.isEmpty()) {
            return;
        }
        for (Integer code : tagCode) {
            Long tagId = articleMapper.findTagByCode(code);
            articleMapper.insertArticleAndTag(articleId,tagId);
        }
    }

}
